package edu.indiana.cs.b534.torrent.impl;

import edu.indiana.cs.b534.torrent.TorrentException;
import edu.indiana.cs.b534.torrent.message.PeerDictionary;
import edu.indiana.cs.b534.torrent.message.TrackerResponse;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Logger;

public class TrackerUpdater extends Thread {
    private TorrentManager manager;
    private Map<String, Boolean> deadPeers;
    private static Logger log = Logger.getLogger(TorrentManager.TORRENT_MANAGER_NAME);

    public TrackerUpdater(TorrentManager manager) {
        super();
        this.manager = manager;
        this.setDaemon(true);
        deadPeers = new Hashtable<String, Boolean>();
    }


    @Override
    public void run() {
        while (true) {
            try {
                TrackerResponse response = manager.updateFromTracker();
                Vector<PeerDictionary> avalibleNonConnectedPeers = manager.getTorrentContext().getAvalibleNonConnectedPeers();
                for (PeerDictionary peer : response.getPeers()) {
                    String key = peer.getIP() + peer.getPort();
                    if (!deadPeers.containsKey(key)) {

                        if (!avalibleNonConnectedPeers.contains(peer)) {
//							System.out.println("Peer "+ peer + "added");
                            avalibleNonConnectedPeers.add(peer);
                        }
                    }
                }
                Thread.sleep(60000);
            } catch (TorrentException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public List<PeerDictionary> findLivePeers(List<PeerDictionary> peers) throws TorrentException {

        List<PeerDictionary> livePeers = new ArrayList<PeerDictionary>();

        for (PeerDictionary peerDictionary : peers) {

            // Create a socket with a timeout
            try {
                if (peerDictionary.getPort() == 0) {
                	deadPeers.put(peerDictionary.getIP() + peerDictionary.getPort(), true);
                    continue;
                }
                InetAddress addr = InetAddress.getByName(peerDictionary.getIP());
                SocketAddress sockaddr = new InetSocketAddress(addr, peerDictionary.getPort());

                // Create an unbound socket
                Socket sock = new Socket();

                // This method will block no more than timeoutMs.
                // If the timeout occurs, SocketTimeoutException is thrown.
                int timeoutMs = 2000;   // 2 seconds
                //log.info("Connecting to "+ peerDictionary.getIP()+":"+peerDictionary.getPort());
                sock.connect(sockaddr, timeoutMs);
                sock.close();
                livePeers.add(peerDictionary);
            } catch (Exception e) {
                deadPeers.put(peerDictionary.getIP() + peerDictionary.getPort(), true);
                log.info("Can not connect to the peer in " + peerDictionary.getIP() + ":" + peerDictionary.getPort());
            }
        }

        //livePeers.add(new PeerDictionaryImpl("127.0.0.1", "-ERAN-SRINATH-SEED-1", 6548));
        return livePeers;
    }

}
